/*------------------------------------------------------------------------------
    File        : ValueCollection
    Purpose     : ICollection implementation over values in an IMap (also TT based) 
                  object that needs collection capabilities.. 
                  used to return Values IMap 
    Syntax      : 
    Description : 
    @author hdaniels
    Created     : 2010
    Notes       : no empty constructor, specialized for IMap 
                 - Changes to the map are reflected here, and vice-versa. 
                 - Supports removal and removes the corresponding map entry from the map
                   (Iterator.remove, Collection.remove, removeAll, retainAll and clear) .
                 - Do not support add and addAll.   
                 - no empty constructor, specialised for IMap 
----------------------------------------------------------------------------------------------*/

routine-level on error undo, throw.
using Progress.Lang.Object.

using OpenEdge.Lang.Collections.ICollection.
using OpenEdge.Lang.Collections.IIterator.
using OpenEdge.Lang.Collections.Iterator.
using OpenEdge.Lang.Collections.IMap.

class OpenEdge.Lang.Collections.ValueCollection implements ICollection: 
    define protected property OwningMap as IMap no-undo get. set.
    
    define public property Size as integer no-undo 
    get():
        return OwningMap:Size.
    end. 
    
    define private variable mhTempTable     as handle no-undo. 
    define private variable mhField         as handle no-undo. 
 
    constructor public ValueCollection(poMap as IMap,phTT as handle, pcValuefield as char):
        super ().
        assign
            mhTempTable = phTT
            mhField = mhTempTable:default-buffer-handle:buffer-field (pcValuefield)
            OwningMap = poMap.
    end constructor.
    
    method public logical Add(newObject as Object ):
        return false.
        /* undo, throw new AppError("Cannot add, use Map:AddAll instead"). */
    end method.

    method public logical AddAll( newCollection as ICollection ):
        return false.
        /* undo, throw new AppError("Cannot addAll, use Map:AddAll instead"). */
    end method.
    
    method public logical AddArray( o as Object extent ):
        return false.
        /* undo, throw new AppError("Cannot addAll, use Map:AddAll instead"). */
    end method.

    method public void Clear(  ):
        OwningMap:Clear().
    end method.
   
    method public logical IsEmpty(  ):
        return OwningMap:IsEmpty().
    end method.

    method public logical Contains( checkObject as Object):
        return OwningMap:ContainsValue(checkObject).
    end method.
    
    /* Returns a new IIterator over the collection. */
    method public IIterator Iterator( ):    
        return new Iterator(this-object,mhTempTable,mhField:name).
    end method.
      
    /* slow... use Remove on Map or Map:KeySet() instead  */
    method public logical Remove( poOld as Object ):
        define variable oIter as IIterator no-undo.
        define variable oKey  as Object    no-undo.
        define variable oVal  as Object    no-undo.
        oIter = OwningMap:KeySet:Iterator().
        do while oIter:HasNext():
            oKey = oIter:Next().
            oVal  = OwningMap:Get(oKey).
            if oVal:Equals(poOld) then
            do:
                OwningMap:Remove(oKey).
                return true.
            end.    
        end.     
        return false.
    end method.
    
    method public logical RemoveAll(poRemoveCol as ICollection):
        define variable oIter as IIterator no-undo.
        define variable oKey  as Object    no-undo.
        define variable oVal  as Object    no-undo.
        define variable lany as logical no-undo.
        oIter = OwningMap:KeySet:Iterator().
        do while oIter:HasNext():
            oKey = oIter:Next().
            oVal  = OwningMap:Get(oKey).
            if poRemoveCol:Contains(oVal) then
            do:  
                OwningMap:Remove(oKey).
                lAny = true.
            end.    
        end.
        return lAny.
    end method.
    
    method public logical RetainAll(poCol as ICollection):
        define variable oIter as IIterator no-undo.
        define variable oKey  as Object    no-undo.
        define variable oVal  as Object    no-undo.
        define variable lany as logical no-undo.
        oIter = OwningMap:KeySet:Iterator().
        do while oIter:HasNext():
            oKey = oIter:Next().
            oVal  = OwningMap:Get(oKey).
            if not poCol:Contains(oVal) then
            do:  
                OwningMap:Remove(oKey).
                lAny = true.
            end.    
        end.
        return lAny.
    end method.
    
    /* ToArray should not be used with large collections
       If there is too much data the ABL will throw:  
       Attempt to update data exceeding 32000. (12371) */
    method public Object extent ToArray():
        define variable i as integer no-undo.
        define variable oObjArray as Object extent no-undo.
        define variable iterator as IIterator no-undo.
        
        if Size eq 0 then
            return oObjArray.
            
        extent(oObjarray) = Size.
        iterator = Iterator(). 
        do while iterator:hasNext():
           i = i + 1.
           oObjArray[i] = iterator:Next().  
        end.                                     
        return oObjArray.
    end method.
    
    method public void ToTable( output table-handle tt ):
        tt = mhTempTable.
    end method. 
end class.